package com.gitee.wsl.mathematics.geometry.d2.triangle.ext

import com.gitee.wsl.mathematics.coordinate.d2.Coordinate2
import com.gitee.wsl.mathematics.geometry.d2.triangle.TriangleShape2d
import com.gitee.wsl.mathematics.number.compareTo
import com.gitee.wsl.mathematics.vector.vec2.Vector2D


/**
 * Test if this triangle is oriented counterclockwise (CCW). Let A, B and C
 * be three 2D points. If det &gt; 0, C lies to the left of the directed
 * line AB. Equivalently the triangle ABC is oriented counterclockwise. When
 * det &lt; 0, C lies to the right of the directed line AB, and the triangle
 * ABC is oriented clockwise. When det = 0, the three points are colinear.
 * See Real-Time Collision Detection, chap. 3, p. 32
 *
 * @return Returns true iff the triangle ABC is oriented counterclockwise
 * (CCW)
 */
fun<T:Number> TriangleShape2d<T, *>.isOrientedCCW(): Boolean {
    val a11 = a.x - c.x
    val a21 = b.x - c.x

    val a12 = a.y - c.y
    val a22 = b.y - c.y

    val det = a11 * a22 - a12 * a21

    return det > zero
}

/**
 * Tests if a given point lies in the circumcircle of this triangle. Let the
 * triangle ABC appear in counterclockwise (CCW) order. Then when det &gt;
 * 0, the point lies inside the circumcircle through the three points a, b
 * and c. If instead det &lt; 0, the point lies outside the circumcircle.
 * When det = 0, the four points are cocircular. If the triangle is oriented
 * clockwise (CW) the result is reversed. See Real-Time Collision Detection,
 * chap. 3, p. 34.
 *
 * @param point
 * The point to be tested
 * @return Returns true iff the point lies inside the circumcircle through
 * the three points a, b, and c of the triangle
 */
fun<T:Number> TriangleShape2d<T, *>.isPointInCircumcircle(point: Coordinate2<T,*>): Boolean {
    val a11 = a.x - point.x
    val a21 = b.x - point.x
    val a31 = c.x - point.x

    val a12 = a.y - point.y
    val a22 = b.y - point.y
    val a32 = c.y - point.y

    val a13 = (a.x - point.x) * (a.x - point.x) + (a.y - point.y) * (a.y - point.y)
    val a23 = (b.x - point.x) * (b.x - point.x) + (b.y - point.y) * (b.y - point.y)
    val a33 = (c.x - point.x) * (c.x - point.x) + (c.y - point.y) * (c.y - point.y)

    val det =
        (a11 * a22 * a33 + a12 * a23 * a31 + a13 * a21 * a32 - a13 * a22 * a31 - a12 * a21 * a33 - a11 * a23 * a32)

    if (isOrientedCCW()) {
        return det > 0.0
    }

    return det < 0.0
}
